using System;
using System.IO;
using System.Net;
using System.Text;

/*	-----------------------------------------------------------------------	
	Copyright:	umlungu consulting (pty) ltd
	Author:		Alan Benington	
	Started:	2005-09-08
	Status:		release
	Version:	1.0.3
	Build:		20070212
	License:	GNU General Public License
	-----------------------------------------------------------------------	*/

/*	-----------------------------------------------------------------------	
	Development Notes:
	==================
	20070212:	This class originated in ScraperX, but has been refactored 
				to be a simple utility class to get the http response from 
				any url.
	20080321:	Added timeout property
	20080321:	Made all httpRequest and httpResponse variables local to
				methods to ensure garbage collection
	-----------------------------------------------------------------------	*/

namespace umlungu.engineX {
/// <summary>Enumerates request types</summary>
	public enum x_requestType {
		/// <summary>get request</summary>
	    Get = 0,
		/// <summary>Post of html form data</summary>
	    HttpPost = 1,
		/// <summary>Post of SOAP request</summary>
	    SoapPost = 2,
		/// <summary>Post of Xml data</summary>
	    XmlPost = 3,
		/// <summary>Other request</summary>
		Other = 4
	}
	/// <summary>
	/// Description of the classX class.
	/// <para>Additional information about the class</para>
	/// </summary>
	public class x_http {
		#region Invisible properties
		#endregion

		#region Constants
		private const int DEFAULT_TIMEOUT = 100000;	// same as .Net default for HttpWebRequest
		private const string error_nullurl		= "Error:: no url for xml";
		private const string error_get_read		= "Error:: reading xml: ";
		private const string error_post			= "Error:: posting http: ";
		private const string error_post_webex	= "Error:: web exception: ";
		#endregion

		#region Visible properties
		private x_requestType requestType = x_requestType.Get;
		/// <summary>Definiton of the property</summary>
		/// <value>Description of the value of the property</value>
		public x_requestType RequestType {
			get { return requestType; }
			set { requestType = value; }
		}
		private string url;
		/// <summary>The page's url</summary>
		/// <value>A url string</value>
		public string Url {
			get { return url; }
			set { url = value; }
		}
		private string response;
		/// <summary>The url's xml</summary>
		/// <value>A string containing the xml of the url</value>
		public string Response {
			get { return response; }
			set {response = value; }
		}
		private int timeout = DEFAULT_TIMEOUT;
		/// <summary>The timeout value of the http request</summary>
		/// <value>Timeout value in milliseconds</value>
		public int Timeout {
			get { return timeout; }
			set { timeout = value; }
		}
		#endregion

		#region Constructors/Destructors
		/// <overloads>Constructor</overloads>
		/// <summary>Default constructor</summary>
		public x_http() {
		}
		/// <summary>Constructor description</summary>
		/// <param name="thisurl">The page's url</param>
		public x_http(string thisurl) {
			url = thisurl;
		}
		#endregion

		#region Public methods
		/// <overloads>Gets the page from the url specified</overloads>
		/// <summary>
		/// The url is supplied
		/// </summary>
		/// <param name="thisurl">The page's url</param>
		public void Get(string thisurl) {
			url = thisurl;
			Get();
		}
		/// <summary>
		/// The url is assumed to have been set
		/// </summary>
		public void Get() {
			getHttp();
		}
		/// <summary>
		/// The url is assumed to have been set
		/// </summary>
		public void GetXml() {
			getXml();
		}
		/// <overloads>Posts to the url specified</overloads>
		/// <summary>The url is supplied</summary>
		/// <param name="thisurl">The  url</param>
		/// <param name="message">The message to be posted</param>
		public void Post(string thisurl, string message) {
			url = thisurl;
			Post(message);
		}
		/// <summary>The url is assumed to have been set</summary>
		/// <param name="message">The message to be posted</param>
		public void Post(string message) {
			requestType = x_requestType.HttpPost;
			postHttp(message);
		}
		/// <overloads>Soaps to the url specified</overloads>
		/// <summary>The url is supplied</summary>
		/// <param name="thisurl">The  url</param>
		/// <param name="message">The message to be posted</param>
		public void Soap(string thisurl, string message) {
			url = thisurl;
			Soap(message);
		}
		/// <summary>The url is assumed to have been set</summary>
		/// <param name="message">The message to be posted</param>
		public void Soap(string message) {
			requestType = x_requestType.SoapPost;
			postHttp(message);
		}
		#endregion
		
		#region Protected methods
		#endregion
				
		#region Private methods
		/// <summary>Original method now deprecated</summary>
		private void getXml() {
			HttpWebRequest searchReq;
			HttpWebResponse searchResp = null;
			StreamReader readStream = null;
			if (url == "")
				throw new x_exception("error_nullurl", error_nullurl);
			
			StringBuilder thisinp = new StringBuilder();
			try {
				searchReq = (HttpWebRequest)WebRequest.Create(url);
				searchResp = (HttpWebResponse)searchReq.GetResponse();
	
				// Gets the stream associated with the response.
	            Stream receiveStream = searchResp.GetResponseStream();
	            Encoding encode = System.Text.Encoding.GetEncoding("utf-8");
	            // Pipes the stream to a higher level stream reader with the required encoding format. 
	            readStream = new StreamReader( receiveStream, encode );
				
	            Char[] read = new Char[1024];
	              // Reads 1024 characters at a time
	            int count = 1, thiscnt = 0;
	            while (count > 0) {
					count = readStream.Read(read, 0, 1024);
					thisinp.Append(read, 0, count);
					thiscnt += count;
            	}
			} catch(Exception e) {
				throw new x_exception("error_get_read", String.Concat(error_get_read, e.Message));
			} finally {
				if (searchResp != null)
	            	searchResp.Close();
				if (readStream != null)
		            readStream.Close();			
			}
			response = thisinp.ToString();
		}
		/// <overloads>Makes a http post data and get a response form a url</overloads>
		/// <summary></summary>
		private void postHttp(string reqestString) {
			postHttp(reqestString, true);
		}
		/// <summary>makes a http post data and get a response form a url</summary>
		private void postHttp(string reqestString, bool isSoap) {
			HttpWebRequest httpRequest;
			HttpWebResponse httpResponse = null;
			response = null;
			if (url == "")
				throw new x_exception("error_nullurl", error_nullurl);
			try {
				httpRequest = (HttpWebRequest)WebRequest.Create(url);
				httpRequest.Timeout = timeout;
				if (isSoap)
					httpRequest.Headers.Add("SOAPAction","\"\"");
				
				httpRequest.ContentType = contentType();
				httpRequest.Accept = "*/*";
				httpRequest.Method = "POST";
				httpRequest.ContentLength = reqestString.Length;
				httpRequest.KeepAlive = true;
				
				using (Stream requestStream = httpRequest.GetRequestStream()) {
					byte[] requestBytes = getBytes(reqestString);
					requestStream.Write(requestBytes, 0, requestBytes.Length);
					using (httpResponse = (HttpWebResponse)httpRequest.GetResponse()) {
						//throw new x_exception("error_post", String.Concat(error_post, " :: response:", (httpResponse == null)? "null response" : stream2string(httpResponse.GetResponseStream())));
						readResponse(httpResponse.GetResponseStream());
					}
					requestStream.Close();
				}
			} catch(WebException e) {
				HttpWebResponse exresponse = (HttpWebResponse)e.Response;
				//throw new x_exception("error_post_webex", String.Concat(error_post_webex, e.Message, " [at: ", e.StackTrace, "] :: response:'--", (exresponse == null)? "null response" : stream2string(exresponse.GetResponseStream()), "--'"));
				if (exresponse != null) {
					if (exresponse.StatusCode == HttpStatusCode.Unauthorized) {
						string challenge = null;
						challenge = exresponse.GetResponseHeader("WWW-Authenticate");
						if (challenge != null)
							throw new x_exception("error_post_webex", String.Concat(error_post_webex, "The following challenge was raised by the server:", challenge));
					} else {
						throw new x_exception("error_post_webex", String.Concat(error_post_webex, e.Message, " [status: ", e.Status.ToString(), "] code:", exresponse.StatusCode, " desc:", exresponse.StatusDescription));
						//throw new x_exception("error_post_webex", String.Concat(error_post_webex, e.Message, " [at: ", e.StackTrace, "] :: response:'--", (exresponse == null)? "null response" : stream2string(exresponse.GetResponseStream()), "--'"));
					}
				} else {
					throw new x_exception("error_post_webex", String.Concat(error_post_webex, "Response Received from server was null:", e.Message, " [status:", e.Status.ToString(), "]"));
				}
			} catch (x_exception e) {
				throw e;
			} catch (Exception e) {
				throw new x_exception("error_post", String.Concat(error_post, e.Message, " [at: ", e.StackTrace, "] :: response:", (httpResponse == null)? "null response" : stream2string(httpResponse.GetResponseStream())));
			}
		}
		/// <summary>makes a http get request to a url</summary>
		private void getHttp() {
			HttpWebRequest httpRequest;
			HttpWebResponse httpResponse;
			response = null;
			if (url == "")
				throw new x_exception("error_nullurl", error_nullurl);
			try {
				httpRequest = (HttpWebRequest)WebRequest.Create(url);
				httpRequest.Timeout = timeout;
				using (httpResponse = (HttpWebResponse)httpRequest.GetResponse()) {
					readResponse(httpResponse.GetResponseStream());
				}
			} catch (Exception e){
                throw new x_exception("error_get_read", String.Concat(error_get_read, "::e.type:", e.GetType().ToString(), "::e.Message:", e.Message, "::e:", e.ToString()));
			}
		}
		private void readResponse(Stream responseStream) {
			StringBuilder responseString = new StringBuilder();
			Encoding encode = System.Text.Encoding.GetEncoding("utf-8");
			// Pipes the stream to a higher level stream reader with the required encoding format. 
			using (StreamReader readStream = new StreamReader(responseStream, encode )) {
				Char[] read = new Char[1024];
				  // Reads 1024 characters at a time
				int count = 1, thiscnt = 0;
				while (count > 0) {
					count = readStream.Read(read, 0, 1024);
					responseString.Append(read, 0, count);
					thiscnt += count;
				}
			}
			response = responseString.ToString();
		}
		private string contentType() {
			string typestr = "";
			switch (requestType) {
				case x_requestType.HttpPost:	typestr = "application/x-www-form-urlencoded";	break;
				case x_requestType.SoapPost:	//typestr = "application/soap+xml;charset=iso-8859-1";	break;
				case x_requestType.XmlPost:		typestr = "text/xml;charset=utf-8";	break;
			}
			return typestr;
		}
		private byte[] getBytes(string input) {
			byte[] output = null;
			Encoding encoding = null;
			switch (requestType) {
				case x_requestType.HttpPost:	encoding = new ASCIIEncoding();
												output = encoding.GetBytes(input);
												break;
				case x_requestType.SoapPost:
				case x_requestType.XmlPost:		encoding = new UTF8Encoding();
												output = encoding.GetBytes(input);
												break;
			}
			return output;
		}
		private string stream2string(Stream receiveStream) {
			StringBuilder thisinp = new StringBuilder();
			try {
	            Encoding encode = Encoding.GetEncoding("utf-8");
	            StreamReader readStream = new StreamReader(receiveStream, encode);
				
	            Char[] read = new Char[1024];
	              // Reads 1024 characters at a time
	            int count = 1, thiscnt = 0;
	            while (count > 0) {
					count = readStream.Read(read, 0, 1024);
					thisinp.Append(read, 0, count);
					thiscnt += count;
            	}
				return thisinp.ToString();
			} catch (Exception e) {
				return String.Concat("Error (getRequest):", e.Message);
			}
		}
		#endregion
	}
}
